from flask import Flask, render_template, request, jsonify
import pandas as pd
import numpy as np
import os
import pickle  # 改用pickle加载模型
import sys

app = Flask(__name__)

# 更灵活地查找模型文件
def find_model_files():
    # 可能的模型路径
    possible_model_paths = [
        # 当前文件夹中的models目录
        os.path.join('models', 'diabetes_rf_model.pkl'),
        # 当前工作目录中的models目录
        os.path.join(os.getcwd(), 'models', 'diabetes_rf_model.pkl'),
        # 父级目录中的models目录 
        os.path.join(os.path.dirname(os.getcwd()), 'models', 'diabetes_rf_model.pkl'),
        # flask_diabetes_app/models目录
        os.path.join('flask_diabetes_app', 'models', 'diabetes_rf_model.pkl'),
        # 绝对路径（以防万一）
        os.path.join(os.path.dirname(os.path.abspath(__file__)), 'models', 'diabetes_rf_model.pkl')
    ]
    
    # 可能的模型信息路径
    possible_info_paths = [
        # 当前文件夹中的models目录
        os.path.join('models', 'diabetes_rf_model_info.pkl'),
        # 当前工作目录中的models目录
        os.path.join(os.getcwd(), 'models', 'diabetes_rf_model_info.pkl'),
        # 父级目录中的models目录
        os.path.join(os.path.dirname(os.getcwd()), 'models', 'diabetes_rf_model_info.pkl'),
        # flask_diabetes_app/models目录
        os.path.join('flask_diabetes_app', 'models', 'diabetes_rf_model_info.pkl'),
        # 绝对路径（以防万一）
        os.path.join(os.path.dirname(os.path.abspath(__file__)), 'models', 'diabetes_rf_model_info.pkl')
    ]
    
    # 查找有效的模型文件路径
    model_path = None
    for path in possible_model_paths:
        if os.path.exists(path):
            model_path = path
            break
            
    # 查找有效的模型信息文件路径
    info_path = None
    for path in possible_info_paths:
        if os.path.exists(path):
            info_path = path
            break
    
    return model_path, info_path

# 尝试查找模型文件
MODEL_PATH, INFO_PATH = find_model_files()

# 打印调试信息
print(f"当前工作目录: {os.getcwd()}")
print(f"查找到的模型路径: {MODEL_PATH}")
print(f"查找到的模型信息路径: {INFO_PATH}")

# 模型文件检查
if not MODEL_PATH or not INFO_PATH:
    print("警告: 模型文件未找到。将使用模拟数据进行预测。")
    # 设置默认特征和阈值，用于模拟预测
    features = ['Pregnancies', 'Glucose', 'BloodPressure', 'SkinThickness', 
               'Insulin', 'BMI', 'DiabetesPedigreeFunction', 'Age']
    threshold = 0.5
    model = None
    model_info = None
else:
    try:
        # 加载模型和模型信息
        with open(MODEL_PATH, 'rb') as f:
            model = pickle.load(f)
        
        with open(INFO_PATH, 'rb') as f:
            model_info = pickle.load(f)
        
        # 获取特征和阈值
        features = model_info['features']
        threshold = model_info['best_threshold']
        print("模型和特征信息加载成功！")
    except Exception as e:
        print(f"加载模型文件时出错: {e}")
        # 设置默认特征和阈值，用于模拟预测
        features = ['Pregnancies', 'Glucose', 'BloodPressure', 'SkinThickness', 
                   'Insulin', 'BMI', 'DiabetesPedigreeFunction', 'Age']
        threshold = 0.5
        model = None
        model_info = None

def predict_diabetes(patient_data):
    """基于输入的患者数据预测糖尿病风险"""
    # 将输入数据转换为DataFrame
    if isinstance(patient_data, dict):
        data = pd.DataFrame([patient_data])
    else:
        data = patient_data
    
    # 确保数据包含所有需要的特征且顺序正确
    data = data[features]
    
    # 使用模型进行预测
    if model is not None:
        try:
            probability = model.predict_proba(data)[0, 1]
            prediction = 1 if probability >= threshold else 0
        except Exception as e:
            print(f"预测时出错: {e}")
            # 出错时使用随机预测
            import random
            probability = random.uniform(0, 1)
            prediction = 1 if probability >= threshold else 0
    else:
        # 如果没有模型，使用随机预测
        import random
        probability = random.uniform(0, 1)
        prediction = 1 if probability >= threshold else 0
    
    # 风险等级
    if probability < 0.4:
        risk_level = "低风险"
        risk_class = "low-risk"
    elif probability < 0.7:
        risk_level = "中风险"
        risk_class = "medium-risk"
    else:
        risk_level = "高风险"
        risk_class = "high-risk"
    
    # 返回结果
    result = {
        'prediction': prediction,
        'probability': probability,
        'risk_level': risk_level,
        'risk_class': risk_class,
        'prediction_text': '阳性' if prediction == 1 else '阴性'
    }
    
    return result

@app.route('/')
def index():
    """渲染主页/输入表单"""
    return render_template('index.html', features=features)

@app.route('/predict', methods=['POST'])
def predict():
    """处理表单提交并返回预测结果"""
    try:
        # 从表单获取数据
        patient_data = {}
        for feature in features:
            value = request.form.get(feature)
            if value is None or value == '':
                return render_template('index.html', features=features, 
                                      error=f"请提供 {feature} 的值"), 400
            patient_data[feature] = float(value)
        
        # 获取预测结果
        result = predict_diabetes(patient_data)
        
        # 添加输入数据供结果页面显示
        result['patient_data'] = patient_data
        
        # 渲染结果页面
        return render_template('result.html', result=result)
    
    except ValueError as e:
        return render_template('index.html', features=features, 
                              error=f"无效输入: {str(e)}"), 400
    except Exception as e:
        return render_template('index.html', features=features, 
                              error=f"预测错误: {str(e)}"), 500

@app.route('/api/predict', methods=['POST'])
def api_predict():
    """API端点，接收JSON数据并返回JSON预测结果"""
    try:
        # 从请求中获取JSON数据
        data = request.get_json()
        if not data:
            return jsonify({'error': '未提供数据'}), 400
        
        # 检查必要的特征
        for feature in features:
            if feature not in data:
                return jsonify({'error': f'缺少特征: {feature}'}), 400
        
        # 获取预测结果
        result = predict_diabetes(data)
        
        # 返回JSON响应
        return jsonify({
            'success': True,
            'prediction': result['prediction'],
            'probability': float(result['probability']),
            'risk_level': result['risk_level'],
            'prediction_text': result['prediction_text']
        })
    
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/feature-importance')
def feature_importance():
    """显示特征重要性页面"""
    # 使用模型信息中的特征重要性数据
    if model_info is not None and 'feature_importance' in model_info:
        importance_df = model_info['feature_importance']
        return render_template('feature_importance.html', importance=importance_df.to_dict('records'))
    else:
        # 如果没有模型信息，使用模拟数据
        sample_importance = [
            {'feature': 'Glucose', 'importance': 0.25},
            {'feature': 'BMI', 'importance': 0.19},
            {'feature': 'Age', 'importance': 0.15},
            {'feature': 'DiabetesPedigreeFunction', 'importance': 0.12},
            {'feature': 'Insulin', 'importance': 0.09},
            {'feature': 'BloodPressure', 'importance': 0.08},
            {'feature': 'Pregnancies', 'importance': 0.07},
            {'feature': 'SkinThickness', 'importance': 0.05}
        ]
        return render_template('feature_importance.html', importance=sample_importance)

if __name__ == '__main__':
    app.run(debug=True) 